﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using EnvDTE;
using Microsoft.VisualStudio.Shell.Interop;

namespace TellagoInc.VsTagExplorer
{
    /// <summary>
    ///   Interaction logic for MyControl.xaml
    /// </summary>
    public partial class MyControl : UserControl
    {
        private readonly DTE _dte;
        private readonly SVsSolution _solution;

        public MyControl(DTE dte, SVsSolution solution)
        {
            _dte = dte;
            _solution = solution;
            InitializeComponent();
        }

        public IEnumerable<string> TagsFilter { get; private set; }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TagsTree.Items.Clear();
            TagsFilter =
                txtTagFilter.Text.Split(' ').Select(t => t.Trim()).Where(t => !string.IsNullOrWhiteSpace(t)).ToArray();

            if (_dte.Solution == null || !_dte.Solution.IsOpen) return;
            Solution solution = _dte.Solution;
            foreach (object project in solution.Projects)
            {
                NavigateProject((Project) project);
            }
        }

        private void NavigateProject(Project project)
        {
            IVsHierarchy hierarchy;
            ((IVsSolution) _solution).GetProjectOfUniqueName(project.UniqueName, out hierarchy);

            var buildPropertyStorage = hierarchy as IVsBuildPropertyStorage;
            
            foreach (ProjectItem item in project.ProjectItems)
            {
                if (buildPropertyStorage != null)
                {
                    NavigateProjectItem(hierarchy, buildPropertyStorage, item);
                }
                else
                {
                    if (item.Object is Project) NavigateProject(item.Object as Project);
                }

            }
        }

        private void NavigateProjectItem(IVsHierarchy hierarchy, IVsBuildPropertyStorage buildPropertyStorage,
                                         ProjectItem rootItem)
        {
            if (rootItem == null || rootItem.Properties == null) return;

            if (rootItem.ProjectItems != null)
            {
                foreach (object item in rootItem.ProjectItems)
                {
                    NavigateProjectItem(hierarchy, buildPropertyStorage, item as ProjectItem);
                }
            }

            string fullPath = rootItem.Properties
                .Cast<Property>()
                .Where(p => p.Name == "FullPath")
                .Select(p => p.Value.ToString())
                .FirstOrDefault();

            if (string.IsNullOrEmpty(fullPath)) return;

            uint itemId = 0;
            hierarchy.ParseCanonicalName(fullPath, out itemId);
            string tags;
            buildPropertyStorage.GetItemAttribute(itemId, "Tags", out tags);

            if (string.IsNullOrEmpty(tags)) return;

            if (!TagsFilter.Any())
            {
                foreach (string tag in tags.Split(' '))
                {
                    AddFileToTag(rootItem, tag);
                }
            }
            else
            {
                if (TagsFilter.All(x => tags.Contains(x)))
                {
                    AddFileToTag(rootItem, string.Join(" ", TagsFilter));
                }
            }
        }

        private void AddFileToTag(ProjectItem projectItem, string tag)
        {
            foreach (object item in TagsTree.Items)
            {
                var node = item as TreeViewItem;
                if (node == null) continue;

                if ((string) node.Header == tag)
                {
                    var newNode = new TreeViewItem {Header = projectItem.Name, DataContext = projectItem};
                    newNode.MouseDoubleClick += TagsNode_MouseDoubleClick;
                    newNode.KeyUp += TagsNode_KeyUp;
                    node.Items.Add(newNode);
                    return;
                }
            }

            var tagNode = new TreeViewItem {Header = tag};
            var childNode = new TreeViewItem {Header = projectItem.Name, DataContext = projectItem};
            childNode.MouseDoubleClick += TagsNode_MouseDoubleClick;
            childNode.KeyUp += TagsNode_KeyUp;
            tagNode.Items.Add(childNode);
            TagsTree.Items.Add(tagNode);
        }

        private void TagsNode_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                OpenSelectedFile();
            }
        }

        private void TagsNode_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            OpenSelectedFile();
        }

        private void OpenSelectedFile()
        {
            var selected = TagsTree.SelectedItem as TreeViewItem;
            if (selected == null) return;

            var item = selected.DataContext as ProjectItem;
            if (item == null) return;

            var path = item.Properties.Item("FullPath").Value as string;
            if (string.IsNullOrWhiteSpace(path)) return;

            _dte.ItemOperations.OpenFile(path);
        }
    }
}